package com.siashan.toolkit.sms.chinamobile.core;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.siashan.toolkit.sms.core.entity.*;
import com.siashan.toolkit.sms.core.exception.Unisms4jException;
import com.siashan.toolkit.sms.core.executor.AbstractSmsSendExecutor;
import com.siashan.toolkit.sms.core.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import sun.net.www.protocol.https.DefaultHostnameVerifier;

import java.util.*;

/**
 * 移动云短信通知执行器
 *
 * @author siashan
 * @since v1.0.1
 **/
@Slf4j
public class ChinaMobileSmsSendExecutor extends AbstractSmsSendExecutor {


    /**
     * Jackson系列化
     */
    private final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 移动云短信配置
     */
    private ChinaMobileSmsConfig chinaMobileSmsConfig;

    /**
     * HttpClient客户端
     */
    private final CloseableHttpClient client;

    /**
     * 构造移动云短信发送处理
     *
     * @param config 移动云短信配置
     */
    public ChinaMobileSmsSendExecutor(ChinaMobileSmsConfig config) {
        super(config);
        this.chinaMobileSmsConfig = config;
        this.client = buildHttpclient();
    }
    /**
     * 构造移动云短信发送处理
     *
     * @param config 移动云短信配置
     */
    public ChinaMobileSmsSendExecutor(ChinaMobileSmsConfig config,Map<String, SmsTemplate> templateMap) {
        this(config);
        this.templateMap = templateMap;
    }

    /**
     * 构造移动云短信发送处理
     *
     * @param config 移动云短信配置
     */
    public ChinaMobileSmsSendExecutor(ChinaMobileSmsConfig config,Map<String, SmsTemplate> templateMap,SmsWhiteList whiteList) {
        this(config,templateMap);
        this.whiteList = whiteList;
    }

    /**
     * 构造移动云短信发送处理
     *
     * @param config 移动云短信配置
     */
    public ChinaMobileSmsSendExecutor(ChinaMobileSmsConfig config,Map<String, SmsTemplate> templateMap,SmsWhiteList whiteList,SmsFrequencyLimitConfig frequencyLimit) {
        this(config,templateMap,whiteList);
        this.frequencyLimit = frequencyLimit;
    }


    /**
     * 发送批量通知
     *
     * @param smsSendModel 通知参数
     * @return 是否发送成功
     */
    @Override
    public boolean doSend(SmsModel smsSendModel) {
        // 短信接收手机号
        String mobiles = StringUtils.join(smsSendModel.getPhones(), ",");

        String paramsString = buildTemplateParas(smsSendModel.getParams());
        ChinaMobileRequest request = new ChinaMobileRequest();
        request.setApId(chinaMobileSmsConfig.getApId());
        request.setEcName(chinaMobileSmsConfig.getEcName());
        request.setSecretKey(chinaMobileSmsConfig.getSecretKey());
        request.setMobiles(mobiles);
        request.setParams(paramsString);
        request.setSign(smsSendModel.getSignName());
        request.setTemplateId(smsSendModel.getTemplateId());
        // 1、顺序不能放错，必须是前面参数设置完成后才能设置mac
        request.setMac(request.genMac());
        // 2、顺序不能放错，必须是参数设置完毕才能执行该步骤
        String encodeBody = request.genEncodeBody();

        // 执行请求
        try {
            HttpResponse response = client.execute(
                    RequestBuilder.create("POST").setUri(chinaMobileSmsConfig.getUri()).setEntity(new StringEntity(encodeBody))
                            .build());
            String responseContent = EntityUtils.toString(response.getEntity());
            log.debug("responseContent: {}", responseContent);
            ChinaMobileResponse result = objectMapper.readValue(responseContent, ChinaMobileResponse.class);
            boolean succeed = ChinaMobileResponse.SUCCESS_RSPCOD.equals(result.getRspcod());
            return succeed;
        } catch (Exception e) {
            log.warn(e.getLocalizedMessage(), e);
            return false;
        }
    }

    /**
     * 构造模板参数
     *
     * @param params 参数列表
     * @return 模板参数
     */
    private String buildTemplateParas(Map<String, String> params, String paramMapping) {
        if (params == null || params.isEmpty()) {
            return null;
        }
        List<String> paramsWithoutKey = transferParamsWithoutKey(params, paramMapping);
        String valueAsString = null;
        try {
            valueAsString = objectMapper.writeValueAsString(paramsWithoutKey);
        } catch (JsonProcessingException e) {
            throw new Unisms4jException("[移动云短信]发送失败", e);
        }

        return valueAsString;
    }

    /**
     * 构造模板参数
     *
     * @param params 参数列表
     * @return 模板参数
     */
    private String buildTemplateParas(Map<String, String> params) {
        if (params == null || params.isEmpty()) {
            return null;
        }
        List<String> paramsWithoutKey = transferParamsWithoutKey(params);
        String valueAsString = null;
        try {
            valueAsString = objectMapper.writeValueAsString(paramsWithoutKey);
        } catch (JsonProcessingException e) {
            throw new Unisms4jException("[移动云短信]发送失败", e);
        }

        return valueAsString;
    }

    public List<String> transferParamsWithoutKey(Map<String, String> srcParam) {
        List<String> parmList = new ArrayList<>();
        Set<String> keySet = srcParam.keySet();
        Iterator<String> iterator = keySet.iterator();
        while (iterator.hasNext()) {
            parmList.add(srcParam.get(iterator.next()));
        }
        return parmList;
    }


    /**
     * 初始化HttpClient
     *
     * @return CloseableHttpClient
     */
    private CloseableHttpClient buildHttpclient() {
        //如果JDK版本是1.8,可使用如下代码
        try {
            CloseableHttpClient client = HttpClients.custom()
                    .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null,
                            (x509CertChain, authType) -> true).build())
                    .setSSLHostnameVerifier(new DefaultHostnameVerifier())
                    .build();
            return client;
        } catch (Exception e) {
            e.printStackTrace();
            throw new Unisms4jException("[移动云短信]初始化HttpClient异常！");
        }
    }

    /**
     * 获取通道
     *
     * @return 通道
     */
    @Override
    public SmsChannel getChannel() {
        return SmsChannel.CHINAMOBILE;
    }


}
